
// C includes
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>

// Gtk2.0
#include "gtk/gtk.h"
#include "gdk-pixbuf/gdk-pixbuf.h"
#include <glib.h>

#include "opencv/cv.hpp"
#include "opencv/cxcore.hpp"
#include "glade/glade.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"

// LibFreeImage
#include "FreeImage.h"

// project
#include "vicon.h"


GladeXML *xml;
GtkWidget *widget;

gint t = 0;
IplImage* opencvImage;
GdkPixbuf* pix;
CvCapture* capture;
FIBITMAP *main_icon;

// Create memory for calculations
static CvMemStorage* storage = 0;

// Create a new Haar classifier
static CvHaarClassifierCascade* cascade = 0;

// Function prototype for detecting and drawing an object from an image
void detect_and_draw( IplImage* image );

// Create a string that contains the cascade name
const char* cascade_name =
    "/home/dexter/opencv_test/trunk.mv/opencv/data/haarcascades/haarcascade_frontalface_alt.xml";
/*    "haarcascade_profileface.xml";*/

void showError(int argc, char *argv[]);

static gboolean time_handler( GtkWidget *widget )
{
    return TRUE;
}

void destroy(GtkWidget * widget, gpointer data) {
        gtk_main_quit();
}

gboolean expose_event_callback( GtkWidget *widget, GdkEventExpose *event,gpointer data)
{

    GdkImage *image;
    GdkVisual *visual;
    int i;
    int j;
    int x;

    gtk_widget_queue_draw( GTK_WIDGET( widget ));
    opencvImage = cvQueryFrame( capture );

    CvScalar color = CV_RGB(0,128,0);
    CvPoint pt1 = cvPoint(0, opencvImage->height/2);
    CvPoint pt2 = cvPoint(opencvImage->width, opencvImage->height/2);

    //cvLine(CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int lineType=8, int shift=0 )
    cvLine(opencvImage, pt1, pt2, CV_RGB(0,128,0),1, CV_AA, 0 );

    pt1 = cvPoint(opencvImage->width/2, 0);
    pt2 = cvPoint(opencvImage->width/2, opencvImage->height);
    cvLine(opencvImage, pt1, pt2, CV_RGB(0,128,0),1, CV_AA, 0 );

    return TRUE;
    detect_and_draw(opencvImage);

   //cvCvtColor( opencvImage, opencvImage, CV_BGR2RGB );


   /*
   pix = gdk_pixbuf_new_from_data(( guchar* )opencvImage->imageData,
                                             GDK_COLORSPACE_RGB,
                                             FALSE,
                                             opencvImage->depth,
                                             opencvImage->width,
                                             opencvImage->height,
                                             ( opencvImage->widthStep ),
                                             NULL, NULL);

    */
        FIBITMAP *dib = NULL;
    dib = FreeImage_AllocateT(FIT_BITMAP, opencvImage->width, opencvImage->height, opencvImage->depth, 0, 0, 0);
    if (dib) {
    printf("bitmap successfully created!\n");
    }

     // create the blue colour
  RGBQUAD blue;
  blue.rgbRed = 255;
  blue.rgbBlue = 255;
  blue.rgbGreen = 0;

  for (i = 0; i < opencvImage->width; i++){
    for (j = 0; j < opencvImage->height; j++){
      // draw a blue pixel at (i, j)
      //FreeImage_SetPixelColor(dib, i, j, &blue);
    }
  }


            visual = gdk_visual_get_system();
            image = gdk_image_new(GDK_IMAGE_NORMAL,visual,opencvImage->width, opencvImage->height);

            if (FreeImage_GetBPP(dib) != (image->bpp << 3)) {
                FIBITMAP *ptr;

                switch (image->bpp) {
                        case 1:
                                ptr = FreeImage_ConvertTo8Bits(dib);
                                break;

                        case 2:
                                if (image->depth == 15) {
                                        ptr = FreeImage_ConvertTo16Bits555(dib);
                                } else {
                                        ptr = FreeImage_ConvertTo16Bits565(dib);
                                }

                                break;
                        case 3:
                                ptr = FreeImage_ConvertTo24Bits(dib);
                                break;

                        default:
                        case 4:
                                ptr = FreeImage_ConvertTo32Bits(dib);
                                break;
                }

                FreeImage_Unload(dib);
                dib = ptr;
        }

//makes it upside down :(
    memcpy(FreeImage_GetBits(dib), opencvImage->imageData, image->bpl * image->height);
    for(i = 0; i < opencvImage->height; i+=1)
    FreeImage_SetPixelColor(dib, 10, i, &blue);

    memcpy(image->mem, FreeImage_GetBits(dib), image->bpl * image->height);

    //memcpy(FreeImage_GetBits(dib), opencvImage->imageData, opencvImage->depth * opencvImage->height);


    //FIBITMAP *display_dib_a = FreeImage_Composite(dib,FALSE, NULL, NULL);

printf("opencvImage->depth: %d\n",opencvImage->depth);
printf("FreeImage_GetColorsUsed: %d\n",FreeImage_GetImageType(dib));
    printf("image->bpl: %d\n",image->bpl);


       pix = gdk_pixbuf_new_from_data(( guchar* )FreeImage_GetBits(dib),
                                             GDK_COLORSPACE_RGB,
                                             FALSE,
                                             opencvImage->depth,
                                             opencvImage->width,
                                             opencvImage->height,
                                             ( opencvImage->widthStep ),
                                             NULL, NULL);

   gdk_draw_pixbuf( widget->window,
                    widget->style->fg_gc[ GTK_WIDGET_STATE( widget )],
                    pix,
                    0, 0, 0, 0,
                    opencvImage->width,
                    opencvImage->height,
                    GDK_RGB_DITHER_MAX,
                    0, 0);

    //FreeImage_Unload(display_dib_a);
    FreeImage_Unload(dib);


   return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// Cute MessageBox                                                           //
///////////////////////////////////////////////////////////////////////////////
void  MessageBox (GtkWindow *parentWindow, char *messageValue)
{
    GtkWidget *dialog;
    dialog = gtk_message_dialog_new (parentWindow, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, messageValue);
    gtk_window_set_title (GTK_WINDOW (dialog), "Information");
    gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_widget_destroy (dialog);
}
///////////////////////////////////////////////////////////////////////////////
// signal handlers                                                           //
///////////////////////////////////////////////////////////////////////////////
void on_mainToolbar_new_clicked(GtkToolItem *TBbutton, GtkWindow *parentWindow);
void on_mainToolbar_new_clicked(GtkToolItem *TBbutton, GtkWindow *parentWindow)
{
    MessageBox(parentWindow, "toolbar tooleditpaste was clicked.");
}
//gboolean on_pixMapArea_expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data);



int main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *drawing_area;
	GdkImage *image;
	FIBITMAP *dib;
	int y;

    /*
    // initialize the FreeImage library
    FreeImage_Initialise(TRUE);

    main_icon = FreeImage_Load(FIF_PNG, "/home/dexter/vlc-icon.png", PNG_DEFAULT);

    printf("pre gtk_init\n");
    gtk_init (&argc, &argv);

    capture = cvCaptureFromCAM( CV_CAP_ANY ); //CV_CAP_ANY
    //capture = cvCreateCameraCapture(0);
    if(!capture) { printf("Capture did not work\n");showError(argc, argv);return 0;}

    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 160 ); //640
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 120 ); //360

    opencvImage = cvQueryFrame( capture );

    printf("opencvImage->width:%d opencvImage->height:%d\n",opencvImage->width, opencvImage->height);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title( GTK_WINDOW( window ), "WEBCAM");
    g_signal_connect( G_OBJECT( window ), "destroy", G_CALLBACK (gtk_main_quit), NULL);
    drawing_area = gtk_drawing_area_new();
    gtk_widget_set_size_request( drawing_area, opencvImage->width, opencvImage->height);
    gtk_container_add( GTK_CONTAINER( window ), drawing_area );
    gtk_widget_show( drawing_area );
    g_signal_connect( G_OBJECT( drawing_area), "expose_event", G_CALLBACK (expose_event_callback), NULL);
    g_timeout_add( 10, ( GSourceFunc )time_handler, ( gpointer )drawing_area );
    gtk_widget_show(window);
    gtk_main();
    cvReleaseCapture( &capture );


    // Dealloc freeimage
    FreeImage_DeInitialise();

    return 0;
    */


    gtk_init(&argc, &argv);

    // import glade file
    GladeXML *main_ui = glade_xml_new("/home/dexter/MyGtkApp/UI.glade", NULL, NULL);
    if(!main_ui)
    {
        printf("Error opening glade xml");
        return 0;
    }
    // get a widget (useful if you want to change something)
    GtkWidget *mainWindow = glade_xml_get_widget(main_ui, "mainWindow");


    // connect signal handlers
    glade_xml_signal_autoconnect(main_ui);
    // process destroy
    g_signal_connect(G_OBJECT(mainWindow), "destroy", G_CALLBACK (gtk_main_quit), NULL);


    // main toolbar actions

    // video toolbar signal handlers
    //GtkToolItem  *tooleditcut ;

    /*
    GtkWidget *mainToolbar = glade_xml_get_widget(main_ui,"mainToolbar");
    GtkToolItem *mainToolbar_new = glade_xml_get_widget(main_ui,"mainToolbar_new");
    gtk_signal_connect(GTK_OBJECT(mainToolbar_new), "button-release-event", GTK_SIGNAL_FUNC(kaka), NULL);

    */

    // Connec

    capture = open_cam(CV_CAP_ANY);

    opencvImage = cvQueryFrame(capture);
    GtkWidget *pixMapArea = glade_xml_get_widget(main_ui,"pixMapArea");
    gtk_widget_set_size_request(pixMapArea, opencvImage->width, opencvImage->height);
    g_signal_connect(G_OBJECT(pixMapArea), "expose_event", G_CALLBACK(on_pixMapArea_expose_event), NULL);

    g_timeout_add( 100, ( GSourceFunc )time_handler, ( gpointer )drawing_area );

    //show widget
    gtk_widget_show(mainWindow);
    gtk_main();
    //cvReleaseCapture( &capture );

    return 0;

}

void showError(int argc, char *argv[])
{
GtkWidget *window, *imagebox;
        GdkVisual *visual;
        GdkImage *image;
        FIBITMAP *dib;
        int y;

        // initialize the FreeImage library
        FreeImage_Initialise(TRUE);

        dib = FreeImage_Load(FIF_PNG, "/home/dexter/freeimage.png", PNG_DEFAULT);

        gtk_init(&argc, &argv);

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

        gtk_signal_connect(GTK_OBJECT(window), "destroy",
                                GTK_SIGNAL_FUNC(destroy), NULL);

        visual = gdk_visual_get_system();

        image = gdk_image_new(GDK_IMAGE_NORMAL,visual,
                FreeImage_GetWidth(dib),FreeImage_GetHeight(dib));

        g_print("picture: %d bpp\n"
                "system:  %d bpp   byteorder: %d\n"
                "  redbits: %d   greenbits: %d   bluebits: %d\n"
                "image:   %d bpp   %d bytes/pixel\n",
                FreeImage_GetBPP(dib),
                visual->depth,visual->byte_order,
                visual->red_prec,visual->green_prec,visual->blue_prec,
                image->depth,image->bpp );

        if (FreeImage_GetBPP(dib) != (image->bpp << 3)) {
                FIBITMAP *ptr;

                switch (image->bpp) {
                        case 1:
                                ptr = FreeImage_ConvertTo8Bits(dib);
                                break;

                        case 2:
                                if (image->depth == 15) {
                                        ptr = FreeImage_ConvertTo16Bits555(dib);
                                } else {
                                        ptr = FreeImage_ConvertTo16Bits565(dib);
                                }

                                break;
                        case 3:
                                ptr = FreeImage_ConvertTo24Bits(dib);
                                break;

                        default:
                        case 4:
                                ptr = FreeImage_ConvertTo32Bits(dib);
                                break;
                }

                FreeImage_Unload(dib);
                dib = ptr;
        }

//makes it upside down :(
      memcpy(image->mem, FreeImage_GetBits(dib), image->bpl * image->height);

/*
        BYTE *ptr = FreeImage_GetBits(dib);

        for (y = 0; y < image->height; y++) {
                memcpy(image->mem + (y * image->bpl),
                        ptr + ((image->height - y - 1) * image->bpl),
                        image->bpl);
        }
*/
        FreeImage_Unload(dib);

        imagebox = gtk_image_new_from_image(image, NULL);
        gtk_container_add(GTK_CONTAINER(window), imagebox);

        gtk_widget_show(imagebox);
        gtk_widget_show(window);

        gtk_main();

        // release the FreeImage library
        FreeImage_DeInitialise();

        return;
}
// Function to detect and draw any faces that is present in an image
void detect_and_draw( IplImage* img )
{
// Create memory for calculations
    static CvMemStorage* storage = 0;

    // Create a new Haar classifier
    static CvHaarClassifierCascade* cascade = 0;

    int scale = 1;

    // Create a new image based on the input image
    IplImage* temp = cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 );

    // Create two points to represent the face locations
    CvPoint pt1, pt2;
    int i;

    // Load the HaarClassifierCascade
    cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );

    // Check whether the cascade has loaded successfully. Else report and error and quit
    if( !cascade )
    {
        fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
        return;
    }

    // Allocate the memory storage
    storage = cvCreateMemStorage(0);

    // Create a new named window with title: result
    //cvNamedWindow( "result", 1 );

    // Clear the memory storage which was used before
    cvClearMemStorage( storage );
    // Find whether the cascade is loaded, to find the faces. If yes, then:
    if( cascade )
    {

        // There can be more than one face in an image. So create a growable sequence of faces.
        // Detect the objects and store them in the sequence
        //1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
        CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,
                                           		1.1,                       // increase search scale by 10% each pass
                                                3,                         // merge groups of three detections
                                                CV_HAAR_DO_CANNY_PRUNING,
                                            cvSize(40, 40), cvSize(0,0));

        // Loop the number of faces found.
        for( i = 0; i < (faces ? faces->total : 0); i++ )
        {
           // Create a new rectangle for drawing the face
            CvRect* r = (CvRect*)cvGetSeqElem( faces, i );

            // Find the dimensions of the face,and scale it if necessary
            pt1.x = r->x*scale;
            pt2.x = (r->x+r->width)*scale;
            pt1.y = r->y*scale;
            pt2.y = (r->y+r->height)*scale;

            // Draw the rectangle in the input image
            cvRectangle( img, pt1, pt2, CV_RGB(0,255,0), 1, CV_AA, 0 );


            CvScalar color = CV_RGB(0,255,0);
            pt1 = cvPoint(0, (r->y+(r->height/2))*scale);
            pt2 = cvPoint(img->width, (r->y+(r->height/2))*scale);

            //cvLine(CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int lineType=8, int shift=0 )
            cvLine(img, pt1, pt2, CV_RGB(0,255,0),1, CV_AA, 0 );

            pt1 = cvPoint((r->x+(r->width/2))*scale, 0);
            pt2 = cvPoint((r->x+(r->width/2))*scale, img->height);
            cvLine(img, pt1, pt2, CV_RGB(0,255,0),1, CV_AA, 0 );
        }
    }

    // Show the image in the window named "result"
    //cvShowImage( "result", img );

    // Release the temp image created.
    cvReleaseImage( &temp );
}
